#light

namespace CGraph.DirectedGraph.Impl

open System.Collections.Generic
open CGraph.DirectedGraph
open CGraph.Generic
open CGraph.Generic.Impl
            
type DirectedGraphObject(m_graph:IDirectedGraph) =
    interface IDirectedGraphObject with
        member this.Graph with get() : IDirectedGraph = m_graph
        
type Vertex(graph:IDirectedGraph) =
    inherit DirectedGraphObject(graph) as base
    let m_incoming : List<IEdge> = new List<IEdge>()
    let m_outgoing : List<IEdge> = new List<IEdge>()
    
    interface IVertex with
        member this.Graph with get() = (base :> IDirectedGraphObject).Graph
        member this.IncomingEdges with get() = m_incoming :> IEnumerable<IEdge>
        member this.OutgoingEdges with get() = m_outgoing :> IEnumerable<IEdge>
        //Probably not an efficient call
        member this.Degree with get() = m_incoming.Count + m_outgoing.Count
        member this.InDegree with get() = m_incoming.Count
        member this.OutDegree with get() = m_outgoing.Count
    
    member this.IncomingList with get() = m_incoming
    member this.OutgoingList with get() = m_outgoing
        
    member this.InternalIncoming with get() = m_incoming :> IEdge seq
    member this.InternalOutgoing with get() = m_outgoing :> IEdge seq

type Edge(graph:IDirectedGraph, incoming:IVertex, outgoing:IVertex) =
    inherit DirectedGraphObject(graph) as base
    let mutable m_incoming : IVertex = incoming
    let mutable m_outgoing : IVertex = outgoing
        
    interface IEdge with
        member this.Graph with get() = (base :> IDirectedGraphObject).Graph
        member this.IncomingVertex with get() = m_incoming
        member this.OutgoingVertex with get() = m_outgoing
        
    member this.InternalIncoming with get() = m_incoming and set(v) = m_incoming <- v
    member this.InternalOutgoing with get() = m_outgoing and set(v) = m_outgoing <- v
    
    
type VertexCollection() =
    let m_vertexes : List<IVertex> = new List<IVertex>()
    interface System.Collections.IEnumerable with
        member this.GetEnumerator() = ((this :> System.Collections.Generic.IEnumerable<IVertex>).GetEnumerator() 
                                                :> System.Collections.IEnumerator)
    
    interface IVertexCollection with
        member this.GetEnumerator() = m_vertexes.GetEnumerator() :> IEnumerator<IVertex>
        member this.Roots with get() = m_vertexes |> Seq.filter( fun(vert) -> vert.InDegree = 0 )
        member this.Leaves 
            with get() = 
                m_vertexes 
                |> Seq.filter( fun(vert) -> 
                    let realVert = vert
                    realVert.OutDegree = 0 && realVert.InDegree <> 0 )
                    
    member this.VertexList with get() = m_vertexes
        
    member this.InternalVertexes with get() = m_vertexes :> IVertex seq

type EdgeCollection(vertex_access:(unit -> seq<IVertex>)) =
    
    interface System.Collections.IEnumerable with
        member this.GetEnumerator() = ((this :> System.Collections.Generic.IEnumerable<IEdge>).GetEnumerator() 
                                                :> System.Collections.IEnumerator)
    interface IEdgeCollection with
        ///All edges in the graph are composed of all the incoming edges
        ///in all of the vertexes of the graph.
        member this.GetEnumerator() = 
            let result = 
                vertex_access() 
                |> Seq.map((fun (vtx:IVertex) -> vtx.IncomingEdges)) 
                |> Seq.concat
             
            result.GetEnumerator()
            
type VertexListAdd = delegate of IVertex*IVertex List->unit
type VertexListRemove = delegate of IVertex*IVertex List->bool
type EdgeListAdd = delegate of IEdge*IEdge List->unit
type EdgeListRemove = delegate of IEdge*IEdge List->bool
        
                   
type DirectedGraph() =
    let mutable m_vertexes = VertexCollection();
    let mutable m_edges = EdgeCollection(fun()-> m_vertexes.VertexList :> IVertex seq);
    let m_addVFire,m_addVEvent = IEvent.create<IVertex*int>()
    let m_remVFire,m_remVEvent = IEvent.create<IVertex*int>()
    // Edge, index in incoming list (outgoing vertex), index in outgoing list (incoming vertex)
    let m_addEFire,m_addEEvent = IEvent.create<IEdge*int*int>()
    // Edge, index in incoming list, index in outgoing list
    let m_remEFire,m_remEEvent = IEvent.create<IEdge*int*int>()
    
    member s.Vertexes with get = m_vertexes and set vt = m_vertexes <- vt
    member s.Edges with get = m_edges and set ed = m_edges <- ed
    member s.VertexAddEvent = m_addVEvent
    member s.VertexRemoveEvent = m_remVEvent
    member s.EdgeAddEvent = m_addEEvent
    member s.EdgeRemoveEvent = m_remEEvent
    
               
    member s.AddVertex vert = 
        let len = m_vertexes.VertexList.Count
        m_vertexes.VertexList.Add vert
        m_addVFire(vert,len)
        
    member s.RemoveVertex vert = 
        let pos = m_vertexes.VertexList.IndexOf vert
        if ( pos <> -1  ) then
            m_vertexes.VertexList.RemoveAt pos
            m_remVFire (vert,pos)
        
    
    member s.AddEdge (edge:IEdge) = 
        let vin = edge.IncomingVertex :?> Vertex
        let vout = edge.OutgoingVertex :?> Vertex
        let inC = vout.IncomingList.Count;
        let outC = vin.OutgoingList.Count;
        vin.OutgoingList.Add edge
        vout.IncomingList.Add edge
        m_addEFire (edge,inC,outC)
        
    member s.RemoveEdge (edge:IEdge) = 
        let vin = edge.IncomingVertex :?> Vertex
        let vout = edge.OutgoingVertex :?> Vertex
        let inC = vout.IncomingList.IndexOf edge;
        let outC = vin.OutgoingList.IndexOf edge;
        if ( outC <> -1 ) then vin.OutgoingList.RemoveAt outC
        if ( inC <> -1 ) then vout.IncomingList.RemoveAt inC
        m_remEFire(edge,inC,outC)
            
    
    interface IDirectedGraph with
        member this.Graph with get() : IDirectedGraph = this :> IDirectedGraph
        member this.Vertexes with get() : IVertexCollection = m_vertexes :> IVertexCollection
        member this.Edges with get() : IEdgeCollection = m_edges :> IEdgeCollection
        ///Inefficient implementation for now.
        member this.Order with get() : int = m_vertexes.VertexList.Count
        member this.Size with get() : int = Seq.length( m_edges )
    
        
     
type VertexCollectionAction(m_graph:DirectedGraph,added:IEnumerable<IVertex>,removed:IEnumerable<IVertex>) =
    inherit CollectionActionBase<IVertex>(added,removed)
    
    override this.PerformAdd( items : seq<IVertex> ) = 
        for item in items do
            m_graph.Vertexes.VertexList.Add(item)
    
    override this.PerformRemove(items : seq<IVertex>) = 
        for item in items do
            m_graph.Vertexes.VertexList.Remove(item) |> ignore
    
    override this.Name with get() = "VertexCollectionAction"
    override this.MergeKey with get() = box(m_graph,this.Name)
    override this.Mergeable with get() = true
    
type EdgeCollectionAction(m_graph:DirectedGraph,added:IEnumerable<IEdge>,removed:IEnumerable<IEdge>) =
    inherit CollectionActionBase<IEdge>(added,removed)
    
    override this.PerformAdd( items : seq<IEdge> ) = 
        for item in items do
            (item.IncomingVertex :?> Vertex).OutgoingList.Add(item)
            (item.OutgoingVertex :?> Vertex).IncomingList.Add(item)
    
    override this.PerformRemove(items : seq<IEdge>) = 
        for item in items do
            (item.IncomingVertex :?> Vertex).OutgoingList.Remove(item) |> ignore
            (item.OutgoingVertex :?> Vertex).IncomingList.Remove(item) |> ignore
    
    override this.Name with get() = "EdgeCollectionAction"
    override this.MergeKey with get() = box(m_graph,this.Name)
    override this.Mergeable with get() = true
        
            
    
    